﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using Eneta.Portal.Common;
using Eneta.Portal.Common.Definitions;
using Eneta.Portal.Common.Dto;
using Eneta.Portal.Common.Helpers;
using Eneta.Portal.Common.Repository;
using Eneta.Portal.Common.Services;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.Utilities;

namespace Eneta.Portal.Events.Controls
{
    public partial class EventEditorControl : UserControl
    {
        private Dictionary<string, string> errors = new Dictionary<string, string>();

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            btnSave.Click += BtnSave_Click;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            var user = SPContext.Current.Web.CurrentUser;
            if (user == null)
            {
                Response.Redirect("/");
                return;
            }
            if (!user.IsSiteAdmin)
            {
                Response.Redirect("/");
                return;
            }

            errors.Clear();

            if (!IsPostBack)
            {
                virtualEventCheckBox.InputAttributes["class"] = "choice";
                realEventCheckBox.InputAttributes["class"] = "choice";
                Bind();
            }
        }

        private void Bind()
        {
            var repository = new EventRepository(EnetaApplication.PortalEventsSiteUrl);
            var audiences = repository.GetAllTargetAudiences();
            targetAudiences.DataSource = audiences;
            targetAudiences.DataBind();

            using (var web = SPContext.Current.Site.OpenWeb(GetWebUrl(SPContext.Current.Site, EnetaApplication.PortalEventsSiteUrl)))
            {
                var ctName = ContentTypes.GetName(ContentTypes.Events);
                var ct = web.AvailableContentTypes[ctName];
                if (ct != null)
                {
                    var levelField = (SPFieldChoice)ct.Fields[EventFields.TechnicalLevel];

                    ddlTechnicalLevel.Items.Add(string.Empty);

                    foreach (var choice in levelField.Choices)
                    {
                        ddlTechnicalLevel.Items.Add(choice);
                    }
                }
                else
                    Logger.LogWarning("EventEditorControl.Bind(): cannot find content type " + ctName);

            }
            if (Item == null)
            {
                //Response.Write("NULL");
                return;
            }
            tbShortDesc.Text = Item.ShortDescription;
            tbPlace.Text = Item.Location;
            tbPlacesCount.Text = Item.MaxAttendees.ToString();
            tbTitle.Text = Item.Title;
            ddlTechnicalLevel.SelectedValue = Item.TechnicalLevel;
            startField.Text = Item.StartTime.ToString("dd.MM.yyyy");
            startHourField.SelectedValue = Item.StartTime.Hour.ToString();
            startMinuteField.Text = Item.StartTime.Minute.ToString();
            endField.Text = Item.EndTime.ToString("dd.MM.yyyy");
            endHourField.SelectedValue = Item.EndTime.Hour.ToString();
            endMinuteField.Text = Item.EndTime.Minute.ToString();

            placeUrlField.Text = Item.LocationUrl;
            realEventCheckBox.Checked = Item.HasRealEvent;
            virtualEventCheckBox.Checked = Item.HasVirtualEvent;
            demosField.Text = Item.PercentOfDemos.ToString();
            slidesField.Text = Item.PercentOfSlides.ToString();
            if (registrationEndDateField == null)
                registrationEndDateField = (TextBox)FindControl("registrationEndDateField");
            registrationEndDateField.Text = Item.RegistrationEndDate.ToString("dd.MM.yyyy");
            descriptionField.Value = Item.Description;

            foreach (var audience in Item.Audiences)
                foreach (ListItem audienceItem in targetAudiences.Items)
                    if (audienceItem.Value == audience)
                        audienceItem.Selected = true;
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            SetCheckStyles(Controls);
        }

        protected void BtnSave_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(tbTitle.Text))
            {
                errors.Add("title", GetResourceString("TitleCannotBeEmpty"));
            }

            if (string.IsNullOrEmpty(tbPlace.Text))
            {
                errors.Add("place", GetResourceString("LocationCannotBeEmpty"));
            }

            if (string.IsNullOrEmpty(tbShortDesc.Text))
            {
                errors.Add("shortDesc", GetResourceString("ShortDescriptionCannotBeEmpty"));
            }

            int placesCount;
            if (string.IsNullOrEmpty(tbPlacesCount.Text))
            {
                errors.Add("placesCount", GetResourceString("MaximumAttendeesCannotBeEmpty"));
            }
            else if (!int.TryParse(tbPlacesCount.Text, out placesCount))
            {
                errors.Add("placesCount", GetResourceString("MaximumAttendeesIsIncorrect"));
            }

            DateTime startDate, endDate, registrationEndDate;
            if (string.IsNullOrEmpty(startField.Text))
            {
                errors.Add("start", GetResourceString("StartTimeCannotBeEmpty"));
            }
            else if (!DateTime.TryParse(startField.Text, out startDate))
            {
                errors.Add("start", GetResourceString("StartTimeIsIncorrect"));
            }

            if (string.IsNullOrEmpty(endField.Text))
            {
                errors.Add("end", GetResourceString("EndTimeCannotBeEmpty"));
            }
            else if (!DateTime.TryParse(endField.Text, out endDate))
            {
                errors.Add("end", GetResourceString("EndTimeIsIncorrect"));
            }

            if (registrationEndDateField == null)
                registrationEndDateField = (TextBox)FindControl("registrationEndDateField");

            if (string.IsNullOrEmpty(registrationEndDateField.Text))
            {
                errors.Add("registrationEndDate", GetResourceString("LastRegistrationDateCannotBeEmpty"));
            }
            else if (!DateTime.TryParse(registrationEndDateField.Text, out registrationEndDate))
            {
                errors.Add("registrationEndDate", GetResourceString("LastRegistrationDateIsIncorrect"));
            }

            if (errors.Count > 0)
            {
                ApplyErrors();
                return;
            }

            string operation;
            try
            {
                AddApproverRoleToUser();
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                return;
            }

            try
            {
                if (Item == null)
                {
                    SavePage();
                    operation = "evtsave";
                }
                else
                {
                    UpdatePage();
                    operation = "evtedit";
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                RemoveApproverRoleFromUser();
                return;
            }

            RemoveApproverRoleFromUser();

            var profileRepositry = new UserProfileRepository(SPContext.Current.Web);
            var loginName = SPContext.Current.Web.CurrentUser.LoginName;
            var profile = profileRepositry.GetUserProfileByUserName(loginName);

            if (Item == null)
            {

                var currentUser = SPContext.Current.Web.CurrentUser;
                try
                {
                    var profileLink = EnetaApplication.PortalProfilePageUrl + "?profileID=" + profile.Id;
                    var mailer = new MailerService();
                    var addresses = new[] { profile.Email, EnetaApplication.PortalModeratorEmail };

                    mailer.SendMailByTemplate("EventInserted", currentUser.Name, tbTitle.Text, profileLink, addresses);
                }
                catch (Exception ex)
                {
                    Logger.LogWarning("Error sending e-mail");
                    Logger.LogException(ex);
                }
            }
            int userId;
            if (IsCurrentUser(out userId))
                Response.Redirect(EnetaApplication.PortalProfileEditPageUrl + "?profileID=" + profile.Id + "&msg=" + operation, false);
            else
                Response.Redirect(EnetaApplication.PortalProfileEditPageUrl + "?profileID=" + profile.Id + "&msg=" + operation, false);
        }

        private void UpdatePage()
        {
            if (!SPContext.Current.Web.CurrentUser.IsSiteAdmin)
                AddApproverRoleToUser();
            var siteId = SPContext.Current.Web.Site.ID;
            using (var site = new SPSite(siteId))
            using (var web = site.OpenWeb(GetWebUrl(site, EnetaApplication.PortalEventsSiteUrl)))
            {
                var listName = PublishingWeb.GetPagesListName(web);
                var list = web.Lists[listName];
                var item = list.GetItemById(Item.Id);
                var status = item.ModerationInformation.Status;

                var dto = new AdminActivityDto();
                dto.PreviousEditor = new SPFieldUserValue(web, item["Editor"].ToString()).User.LoginName;
                dto.PreviousStatus = item.ModerationInformation.Status;
                dto.PreviousTimeStamp = (DateTime)item["Modified"];
                dto.Url = EnetaApplication.PortalEventsSiteUrl + listName + "/" + item["FileLeafRef"];
                dto.Module = "Events";

                var pubItem = PublishingPage.GetPublishingPage(item);
                if (pubItem.ListItem.File.CheckOutStatus == SPFile.SPCheckOutStatus.None)
                    pubItem.CheckOut();
                item["Title"] = tbTitle.Text;
                item[EventFields.Place] = tbPlace.Text;
                item[EventFields.PlaceOnMap] = placeUrlField.Text;
                item[EventFields.ShortDescription] = tbShortDesc.Text;
                item[EventFields.TechnicalLevel] = ddlTechnicalLevel.Text;
                item[EventFields.PlacesCount] = tbPlacesCount.Text;
                item["PublishingPageContent"] = descriptionField.Value;
                item[EventFields.HasRealEvent] = realEventCheckBox.Checked;
                item[EventFields.HasVirtualEvent] = virtualEventCheckBox.Checked;
                //item["TargetAudience"] = audienceList.SelectedValue;
                var audienceValue = new SPFieldMultiChoiceValue();
                foreach (var audience in GetSelectedAudiences())
                    audienceValue.Add(audience);
                item[EventFields.TargetAudience] = audienceValue;

                item[EventFields.PercentOfSlides] = slidesField.Text;
                item[EventFields.PercentOfDemos] = demosField.Text;
                item[EventFields.EventStartDate] = GetDate(startField.Text, startHourField.Text, startMinuteField.Text);
                item[EventFields.EventEndDate] = GetDate(endField.Text, endHourField.Text, endMinuteField.Text);
                var regEnd = DateTime.Parse(registrationEndDateField.Text);
                if (regEnd > DateTime.MinValue)
                    item[EventFields.RegistrationEndDate] = regEnd;
                else
                    item[EventFields.RegistrationEndDate] = null;

                Logger.LogInfo("ESD: " + GetDate(startField.Text, startHourField.Text, startMinuteField.Text));
                Logger.LogInfo("EED: " + GetDate(endField.Text, endHourField.Text, endMinuteField.Text));
                Logger.LogInfo("RED: " + DateTime.Parse(registrationEndDateField.Text));
                item.Update();



                item.File.CheckIn("Muudetud", SPCheckinType.MajorCheckIn);

                if (status == SPModerationStatusType.Approved)
                    item.File.Approve(string.Empty);

                dto.CurrentEditor = new SPFieldUserValue(web, item["Editor"].ToString()).User.LoginName;
                dto.CurrentStatus = item.ModerationInformation.Status;
                dto.CurrentTimeStamp = (DateTime)item["Modified"];
                ActivityLogger.LogActivity(dto);
            }

            if (!SPContext.Current.Web.CurrentUser.IsSiteAdmin)
                RemoveApproverRoleFromUser();
        }


        private bool IsCurrentUser(out int userId)
        {
            string owner = Request.QueryString["Owner"];
            if (string.IsNullOrEmpty(owner))
            {
                userId = -1;
                return true;
            }
            int ownerId;
            if (!int.TryParse(owner, out ownerId))
            {
                userId = -1;
                return true;
            }
            userId = ownerId;
            return false;
        }

        private EventDto _item;
        protected EventDto Item
        {
            get
            {
                if (_item != null)
                    return _item;

                int id;
                int.TryParse(Request.QueryString["EventID"], out id);
                if (id == 0)
                    return null;

                var rep = new EventRepository(EnetaApplication.PortalEventsSiteUrl);
                _item = rep.GetEventById(id);
                return _item;
            }
        }

        private void ApplyErrors()
        {
            foreach (var key in errors.Keys)
            {
                var ctrl = this.FindControl(key + "Container", true) as HtmlGenericControl;
                if (ctrl != null)
                {
                    ctrl.Attributes.Add("class", "info-row failed-info");

                    ctrl = this.FindControl(key + "ErrorMessage", true) as HtmlGenericControl;
                    if (ctrl != null)
                    {
                        ctrl.Style["display"] = string.Empty;
                        ctrl = this.FindControl(key + "ErrorLabel", true) as HtmlGenericControl;
                        if (ctrl != null)
                        {
                            ctrl.InnerText = errors[key];
                        }
                    }
                }
            }
        }

        private void SavePage()
        {
            var siteId = SPContext.Current.Site.ID;
            var webId = SPContext.Current.Web.ID;
            using (var site = new SPSite(siteId))
            {
                using (var web = site.OpenWeb(webId))
                {
                    var page = CurrentID == 0 ? CreatePage(web) : GetPage(web);
                    var item = page.ListItem;

                    item[EventFields.Title] = tbTitle.Text;
                    item[EventFields.Place] = tbPlace.Text;
                    if (!string.IsNullOrEmpty(placeUrlField.Text))
                        item[EventFields.PlaceOnMap] = new SPFieldUrlValue(placeUrlField.Text);
                    else
                        item[EventFields.PlaceOnMap] = null;

                    item[EventFields.ShortDescription] = tbShortDesc.Text;
                    item[EventFields.TechnicalLevel] = ddlTechnicalLevel.Text;
                    item[EventFields.PlacesCount] = tbPlacesCount.Text;
                    item["PublishingPageContent"] = descriptionField.Value;
                    item[EventFields.HasRealEvent] = realEventCheckBox.Checked;
                    item[EventFields.HasVirtualEvent] = virtualEventCheckBox.Checked;

                    var audienceValue = new SPFieldMultiChoiceValue();
                    foreach (var audience in GetSelectedAudiences())
                        audienceValue.Add(audience);
                    item[EventFields.TargetAudience] = audienceValue;

                    item[EventFields.PercentOfSlides] = slidesField.Text;
                    item[EventFields.PercentOfDemos] = demosField.Text;
                    item[EventFields.EventStartDate] = GetDate(startField.Text, startHourField.Text, startMinuteField.Text);
                    item[EventFields.EventEndDate] = GetDate(endField.Text, endHourField.Text, endMinuteField.Text);
                    item[EventFields.RegistrationEndDate] = DateTime.Parse(registrationEndDateField.Text);

                    item.Update();
                    item.File.CheckIn(string.Empty, SPCheckinType.MajorCheckIn);
                    item.File.Update();
                }
            }

            //var profileRepository = new UserProfileRepository(SPContext.Current.Web);
            //var profile = profileRepository.GetUserProfileByUserName(SPContext.Current.Web.CurrentUser.LoginName);
            //Response.Redirect("/profile.aspx?ID=" + profile.Id + "&msg=annsave", false);
        }
        private DateTime GetDate(string dateString, string hourString, string minuteString)
        {
            var date = DateTime.Parse(dateString);
            var hour = int.Parse(hourString);
            var minute = int.Parse(minuteString);
            date = date.AddHours(hour);
            date = date.AddMinutes(minute);

            return date;
        }
        private PublishingPage CreatePage(SPWeb web)
        {
            var publishingWeb = PublishingWeb.GetPublishingWeb(web);

            var ctId = new SPContentTypeId(ContentTypes.Events);
            // TODO: Kui ct on null

            var layouts = publishingWeb.GetAvailablePageLayouts(ctId);
            var newsLayout = layouts[0];
            var listName = PublishingWeb.GetPagesListName(web);
            var list = web.Lists[listName];
            var pages = publishingWeb.GetPublishingPages();

            var pageName = UrlHelper.GetPageFileName(tbTitle.Text);
            var pageUrl = list.RootFolder.ServerRelativeUrl + "/" + pageName;
            var counter = 1;

        checkpage:
            var page = web.GetFile(pageUrl);
            if (page != null)
                if (page.Exists)
                {
                    if (counter == 1)
                        pageUrl = pageUrl.Replace(".aspx", "-1.aspx");
                    else
                        pageUrl = pageUrl.Replace("-" + (counter - 1) + ".aspx", "-" + counter + ".aspx");
                    counter++;
                    goto checkpage;
                }

            var publishingPage = pages.Add(pageUrl, newsLayout);
            var item = publishingPage.ListItem;
            item["ContentTypeId"] = ctId;
            item["Title"] = tbTitle.Text;
            item.Update();
            publishingPage.Update();

            return publishingPage;
        }

        private int _currentID;
        private int CurrentID
        {
            get
            {
                if (_currentID != 0)
                    return 0;

                int.TryParse(Request.QueryString["EventID"] ?? string.Empty, out _currentID);
                return _currentID;
            }
        }

        private PublishingPage GetPage(SPWeb web)
        {
            var listName = PublishingWeb.GetPagesListName(web);
            var list = web.Lists[listName];
            var item = list.GetItemById(CurrentID);

            return PublishingPage.GetPublishingPage(item);
        }

        private void AddApproverRoleToUser()
        {
            var userId = SPContext.Current.Web.CurrentUser.LoginName;
            SPSecurity.RunWithElevatedPrivileges(delegate
            {
                using (var site = new SPSite(EnetaApplication.PortalEventsSiteUrl))
                using (var web = site.OpenWeb(GetWebUrl(site, EnetaApplication.PortalEventsSiteUrl)))
                {
                    web.AllowUnsafeUpdates = true;
                    var pubWeb = PublishingWeb.GetPublishingWeb(web);
                    var pubList = pubWeb.PagesList;

                    var cuser = web.SiteUsers[userId];

                    var assq = from a in pubList.RoleAssignments.Cast<SPRoleAssignment>()
                               from r in a.RoleDefinitionBindings.Cast<SPRoleDefinition>()
                               where a.Member.Name == cuser.LoginName &&
                                     r.Name == EnetaApplication.PortalApproverRoleName
                               select a;

                    if (assq.Count() == 0)
                    {
                        var ass2 = new SPRoleAssignment(cuser);
                        var rb2 = web.RoleDefinitions[EnetaApplication.PortalApproverRoleName];
                        ass2.RoleDefinitionBindings.Add(rb2);
                        pubList.RoleAssignments.Add(ass2);
                        pubList.Update();
                    }
                    web.AllowUnsafeUpdates = false;
                }
            });
        }

        private void RemoveApproverRoleFromUser()
        {
            var userId2 = SPContext.Current.Web.CurrentUser.LoginName;

            SPSecurity.RunWithElevatedPrivileges(delegate
            {
                using (var site = new SPSite(EnetaApplication.PortalEventsSiteUrl))
                using (var web = site.OpenWeb(GetWebUrl(site, EnetaApplication.PortalEventsSiteUrl)))
                {
                    web.AllowUnsafeUpdates = true;
                    var pubWeb = PublishingWeb.GetPublishingWeb(web);
                    var pubList = pubWeb.PagesList;

                    var cuser = web.SiteUsers[userId2];

                    pubList.RoleAssignments.Remove(cuser);
                    pubList.Update();
                    web.AllowUnsafeUpdates = false;
                }
            });
        }

        private static void SetCheckStyles(ControlCollection controls)
        {
            foreach (Control c in controls)
                if (c.GetType() == typeof(CheckBox))
                    ((CheckBox)c).InputAttributes["class"] = "choice";
                else if (c.HasControls())
                    SetCheckStyles(c.Controls);

        }

        private List<string> GetSelectedAudiences()
        {
            var list = new List<string>();
            foreach (ListItem item in targetAudiences.Items)
                if (item.Selected)
                    list.Add(item.Text);

            return list;
        }

        private string GetWebUrl(SPSite site, string webUrl)
        {
            webUrl = webUrl.Replace(site.Url, string.Empty);
            if (!webUrl.StartsWith("/"))
                webUrl = "/" + webUrl;
            return webUrl;
        }
        private string GetResourceString(string label)
        {
            var resourceString = "$Resources:Events," + label;
            var result = SPUtility.GetLocalizedString(resourceString, "Events", SPContext.Current.Web.Language);
            return result;
        }
    }
}
